<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Communication Between Processes
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora167.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora169.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Communication Between Processes</H2><A NAME="sec-com"></A>
The use of processes in application development allows you to delegate
work. Nevertheless, these jobs may not be independent
and it may be necessary for the processes to communicate with each
other.<BR>
<BR>
We introduce two methods of communication between
processes: communication pipes and signals. This chapter
does not discuss all possibilities of process communication.
It is only a first approach to the applications developed in chapters
<A HREF="index.html#chap-PC">19</A> and <A HREF="index.html#chap-PD">20</A>.<BR>
<BR>
<A NAME="toc251"></A>
<H3> Communication Pipes</H3>
<A NAME="@concepts342"></A>
It is possible for processes to communicate directly between each other
in a file oriented style.<BR>
<BR>
Pipes are something like virtual files from which it is possible to read
and to write with the input /&nbsp;output functions
<TT>read</TT> and <TT>write</TT>. They are of limited size, the exact
limit depending from the system. They behave like queues: the first
input is also the first output. Whenever data is read from a pipe,
it is also removed from it.<BR>
<BR>
This queue behavior is realized by the association of
two descriptors with a pipe: one corresponding to the end of the pipe
where new entries are written and one for the end where
they are read. A pipe is created by the function:
<A NAME="@fonctions428"></A>


<PRE><BR># Unix.pipe<CODE> </CODE>;;<BR><CODE>- : unit -&gt; Unix.file_descr * Unix.file_descr = &lt;fun&gt;</CODE><BR>

</PRE>

The first component of the resulting pair is the exit of the pipe
used for reading. The second is the entry of the pipe used for writing.
All processes knowing them can close the descriptors.<BR>
<BR>
Reading from a pipe is blocking, unless all processes knowing
its input descriptor (and therefore able to write to it) have closed it;
in the latter case, the function <TT>read</TT> returns 0.
If a process tries to write to a full pipe, it is
suspended until another process has done a read operation.
If a process tries to write to a pipe while no other process is
available to read from it (all having closed their output
descriptors), the process trying to write receives the signal
<TT>sigpipe</TT>, which, if not indicated otherwise, leads to its
termination. <BR>
<BR>
The following example shows a use of pipes in which grandchildren
tell their process number to their grandparents.<BR>

<PRE>
<B>let</B><CODE> </CODE>output<CODE>,</CODE><CODE> </CODE>input<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.pipe();;<BR><BR><B>let</B><CODE> </CODE>write_pid<CODE> </CODE>input<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"("</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE><TT>(</TT>Unix.getpid<CODE> </CODE>()<TT>)</TT><TT>)</TT><CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>")"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>ignore<CODE> </CODE><TT>(</TT>Unix.write<CODE> </CODE>input<CODE> </CODE>m<CODE> </CODE><CODE>0</CODE><CODE> </CODE><TT>(</TT>String.length<CODE> </CODE>m<TT>)</TT><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.close<CODE> </CODE>input<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix<CODE>.</CODE>Unix_error<TT>(</TT>n<CODE>,</CODE>f<CODE>,</CODE>arg<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"%s(%s) : %s\n"</CODE><CODE> </CODE>f<CODE> </CODE>arg<CODE> </CODE><TT>(</TT>Unix.error_message<CODE> </CODE>n<TT>)</TT><CODE> </CODE>;;<BR><BR><B>match</B><CODE> </CODE>Unix.fork<CODE> </CODE>()<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE><CODE>5</CODE><CODE> </CODE><B>do</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>Unix.fork()<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE>write_pid<CODE> </CODE>input<CODE> </CODE>;<CODE> </CODE>exit<CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.close<CODE> </CODE>input<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE>Unix.close<CODE> </CODE>input;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>""</CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE><CODE> </CODE>buff<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.create<CODE> </CODE><CODE>5</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>Unix.read<CODE> </CODE>output<CODE> </CODE>buff<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>5</CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"My grandchildren are %s\n"</CODE><CODE> </CODE><CODE>!</CODE>s<CODE> </CODE>;<CODE> </CODE>exit<CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE>n<CODE> </CODE>-&gt;<CODE> </CODE>s<CODE> </CODE><CODE>:=</CODE><CODE> </CODE><CODE>!</CODE>s<CODE> </CODE><CODE>^</CODE><CODE> </CODE><TT>(</TT>String.sub<CODE> </CODE>buff<CODE> </CODE><CODE>0</CODE><CODE> </CODE>n<TT>)</TT><CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>"."</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
We obtain the trace:<BR>

<PRE>
<CODE>My grandchildren are (1067.3).(1067.4).(1067.8).(1067.7).(1067.6).(1067.5).</CODE><BR>

</PRE>
<BR>
<BR>
We have introduced points between each part of the sequence read.
This way it is possible to read from the trace the succession
of contents of the pipe. Note how the reading is desynchronized:
whenever an entry is made, even a partial one, it
is consumed.<BR>
<BR>

<H5> Named pipes.</H5>
<A NAME="@concepts343"></A>
Some Unix systems support named pipes, which look as if they were normal files.
It is possible then to communicate between two processes without
a descendence relation using the name of the pipe. The following
function allows you to create such a pipe.
<A NAME="@fonctions429"></A>


<PRE><BR># Unix.mkfifo<CODE> </CODE>;;<BR><CODE>- : string -&gt; Unix.file_perm -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The file descriptors necessary to use the pipe are obtained by
<TT>openfile</TT>, as for usual files, but their behavior is that of
pipes. In particular, the command <TT>lseek</TT> can not be used,
since we have waiting lines.<BR>
<BR>


<H3> Warning </H3> <HR>

<TT>mkfifo</TT> is not implemented for Windows.


<HR>

<BR>
<BR>
<A NAME="toc252"></A>
<H3> Communication Channels</H3>
<A NAME="@concepts344"></A>
The <TT>Unix</TT> module provides a high level function allowing you to
start a program associating with it input or output channels of the
calling program:
<A NAME="@fonctions430"></A>


<PRE><BR># Unix.open_process<CODE> </CODE>;;<BR><CODE>- : string -&gt; in_channel * out_channel = &lt;fun&gt;</CODE><BR>

</PRE>

The argument is the name of the program, or more precisely the
calling path of the program, as we would write it to a command
line interpreter. The string may contain arguments for the program
to execute. The two output values are file descriptors associated
with the standard input / output of the started program. It will
be executed in parallel with the calling program.<BR>
<BR>


<H3> Warning </H3> <HR>

The program started by <TT>open_process</TT> is executed via a call
to the Unix command line interpreter <TT>/bin/sh</TT>.<BR>The use of that function is therefore only possible for systems
that have this interpreter.


<HR>

<BR>
<BR>
We can end the execution of a program started by
<TT>open_process</TT> by using:
<A NAME="@fonctions431"></A>


<PRE><BR># Unix.close_process<CODE> </CODE>;;<BR><CODE>- : in_channel * out_channel -&gt; Unix.process_status = &lt;fun&gt;</CODE><BR>

</PRE>

The argument is the pair of channels associated with a process
we want to close. The return value is the execution status
of the process whose termination we wait.<BR>
<BR>
There are variants of that functions, opening and closing only
one input or output channel:


<PRE><BR># Unix.open_process_in<CODE> </CODE>;;<BR><CODE>- : string -&gt; in_channel = &lt;fun&gt;</CODE><BR># Unix.close_process_in<CODE> </CODE>;;<BR><CODE>- : in_channel -&gt; Unix.process_status = &lt;fun&gt;</CODE><BR># Unix.open_process_out<CODE> </CODE>;;<BR><CODE>- : string -&gt; out_channel = &lt;fun&gt;</CODE><BR># Unix.close_process_out<CODE> </CODE>;;<BR><CODE>- : out_channel -&gt; Unix.process_status = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Here is a nice small example for the use of
<TT>open_process</TT>: we start <TT>ocaml</TT> from <TT>ocaml</TT>!


<PRE><BR># <B>let</B><CODE> </CODE>n_print_string<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>print_string<CODE> </CODE>s<CODE> </CODE>;<CODE> </CODE>print_string<CODE> </CODE><CODE>"(* &lt;-- *)"</CODE><CODE> </CODE>;;<BR><CODE>val n_print_string : string -&gt; unit = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>p<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>oc_in<CODE>,</CODE><CODE> </CODE>oc_out<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.open_process<CODE> </CODE><CODE>"/usr/local/bin/ocaml"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>n_print_string<CODE> </CODE><TT>(</TT>input_line<CODE> </CODE>oc_in<TT>)</TT><CODE> </CODE>;<CODE> </CODE>print_newline()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>n_print_string<CODE> </CODE><TT>(</TT>input_line<CODE> </CODE>oc_in<TT>)</TT><CODE> </CODE>;<CODE> </CODE>print_newline()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_char<CODE> </CODE><TT>(</TT>input_char<CODE> </CODE>oc_in<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_char<CODE> </CODE><TT>(</TT>input_char<CODE> </CODE>oc_in<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>input_line<CODE> </CODE>stdin<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>output_string<CODE> </CODE>oc_out<CODE> </CODE>s<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>output_string<CODE> </CODE>oc_out<CODE> </CODE><CODE>"#quit\n"</CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>oc_out<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.create<CODE> </CODE><CODE>2</CODE><CODE>5</CODE><CODE>0</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>input<CODE> </CODE>oc_in<CODE> </CODE>r<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>2</CODE><CODE>5</CODE><CODE>0</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>n_print_string<CODE> </CODE><TT>(</TT>String.sub<CODE> </CODE>r<CODE> </CODE><CODE>0</CODE><CODE> </CODE>n<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_string<CODE> </CODE><CODE>"Thank you for your visit\n"</CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.close_process<CODE> </CODE><TT>(</TT>oc_in<CODE>,</CODE><CODE> </CODE>oc_out<TT>)</TT><CODE> </CODE>;;<BR><CODE>val p : unit -&gt; Unix.process_status = &lt;fun&gt;</CODE><BR>

</PRE>

The call of the function <TT>p</TT> starts a toplevel
of Objective CAML. We note that it is version 2.03 which is in directory
<TT>/usr/local/bin</TT>. The first four read operations allow us to
get the header, which is shown by toplevel. The line 
<TT>let x = 1.2 +. 5.6;;</TT> is read from the keybard, then sent to
<TT>oc_out</TT> (the output channel bound to the standard input of
the new process). This one evaluates the passed Objective CAML expression
and writes the result to the standard output which is bound to the
input channel <TT>oc_in</TT>. This result is read and written to the output
by the function <TT>input</TT>. Also the string
<CODE>"Thank you for your visit"</CODE> is written to the output.
We send the command #quit;;
to exit the new process.
<PRE>
# p();;
        Objective Caml version 2.03

# let x = 1.2 +. 5.6;;
val x : float = 6.8
Thank you for your visit
- : Unix.process_status = Unix.WSIGNALED 13
# 
</PRE><A NAME="toc253"></A>
<H3> Signals under Unix</H3><A NAME="sec-signals"></A>
<A NAME="@concepts345"></A>
One possibility to communicate with a process is to send it a
signal. A signal may be received at any moment during
the execution of a program. Reception of a signal causes a
logical interruption. The execution of a program is interrupted to
treat the received signal. Then the execution continues at the point
of interruption.
The number of signals is quite restricted (32 under Linux). 
The information carried by a signal is quite rudimentary:
it is only the identity (the number) of the signal.
The processes have a predefined reaction to each signal.
However, the reactions can be redefined for most of the signals.<BR>
<BR>
The data and functions to handle signals are distributed between the
modules <TT>Sys</TT> and <TT>Unix</TT>. The module
<TT>Sys</TT> contains signals conforming to the
POSIX norm (described in [<A HREF="book-ora214.html#Stevens"><CITE>Ste92</CITE></A>]) as well as
some functions to handle signals. The module <TT>Unix</TT>
defines the function <TT>kill</TT> to send a signal. The use of
signals under Windows is restricted to <TT>sigint</TT>.<BR>
<BR>
A signal may have several sources: the keyboard, an illegal attempt to
access memory, etc. A process may send a signal to another by calling
the function
<A NAME="@fonctions432"></A>


<PRE><BR># Unix.kill<CODE> </CODE>;;<BR><CODE>- : int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>

Its first parameter is the PID of the receiver. The second is the signal
which we want to send.<BR>
<BR>

<H4> Handling Signals</H4>
There are three categories of reactions associated with a signal.
For each category there is a constructor of type
<TT>signal_behavior</TT>:<A NAME="@fonctions433"></A>
<UL>
<LI>
 <TT>Signal_default</TT>: the default behavior defined
by the system. In most of the cases this is the termination
of the process, with or without the creation of a file describing
the process state (<TT>core</TT> file).

<LI> <TT>Signal_ignore</TT>: the signal is ignored.

<LI> <TT>Signal_handle</TT>: the behavior is redefined by an
Objective CAML function of type <I>int -&gt; unit</I> which is passed
as an argument to the constructor. For the modified handling
of the signal, the number of the signal is passed to the handling
function.
</UL>On reception of a signal, the execution of the receiving process
is diverted to the function handling the signal. The function
allowing you to redefine the behavior associated with a signal
is provided by the module <TT>Sys</TT>:<A NAME="@fonctions434"></A>


<PRE><BR># Sys.set_signal;;<BR><CODE>- : int -&gt; Sys.signal_behavior -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>

The first argument is the signal to redefine. The second is the
associated behavior.<BR>
<BR>
The module <TT>Sys</TT> provides another modification function
to handle signals:<A NAME="@fonctions435"></A>


<PRE><BR># Sys.signal<CODE> </CODE>;;<BR><CODE>- : int -&gt; Sys.signal_behavior -&gt; Sys.signal_behavior = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
It behaves like <TT>set_signal</TT>, except that it returns in addition
the value associated with the signal before the modification. So we
can write a function returning the behavioral value associated with
a signal. This can be done even without changing this value:


<PRE><BR># <B>let</B><CODE> </CODE>signal_behavior<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>b<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Sys.signal<CODE> </CODE>s<CODE> </CODE>Sys<CODE>.</CODE>Signal_default<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Sys.set_signal<CODE> </CODE>s<CODE> </CODE>b<CODE> </CODE>;<CODE> </CODE>b<CODE> </CODE>;;<BR><CODE>val signal_behavior : int -&gt; Sys.signal_behavior = &lt;fun&gt;</CODE><BR># signal_behavior<CODE> </CODE>Sys.sigint;;<BR><CODE>- : Sys.signal_behavior = Sys.Signal_handle &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
However, the behavior associated with some signals can not be changed.
Therefore our function can not be used for all signals:


<PRE><BR># signal_behavior<CODE> </CODE>Sys.sigkill<CODE> </CODE>;;<BR><CODE>Uncaught exception: Sys_error("Invalid argument")</CODE><BR>

</PRE>
<BR>
<BR>

<H4> Some Signals</H4>
We illustrate the use of some essential signals.<BR>
<BR>

<H5> sigint.</H5><A NAME="@fonctions436"></A>
This signal is generally associated with the key combination
<TT>CTRL-C</TT>. In the following small example we modify the reaction
to this signal so that the receiving process is not interrupted
until the third occurence of the signal.<BR>
<BR>
We create the following file <CODE>ctrlc.ml</CODE>:<BR>

<PRE>
<B>let</B><CODE> </CODE>sigint_handle<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>0</CODE><CODE> </CODE><BR><CODE> </CODE><B>in</B><CODE> </CODE><B>function</B><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>incr<CODE> </CODE>n<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE><CODE>!</CODE>n<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>1</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_string<CODE> </CODE><CODE>"You just pushed CTRL-C\n"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>2</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_string<CODE> </CODE><CODE>"You pushed CTRL-C a second time\n"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>3</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_string<CODE> </CODE><CODE>"If you insist ...\n"</CODE><CODE> </CODE>;<CODE> </CODE>exit<CODE> </CODE><CODE>1</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>()<CODE> </CODE>;;<BR>Sys.set_signal<CODE> </CODE>Sys.sigint<CODE> </CODE><TT>(</TT>Sys<CODE>.</CODE>Signal_handle<CODE> </CODE>sigint_handle<TT>)</TT><CODE> </CODE>;;<BR><B>match</B><CODE> </CODE>Unix.fork<CODE> </CODE>()<CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><CODE> </CODE>()<CODE> </CODE><B>done</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE>pid<CODE> </CODE>-&gt;<CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>1</CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigint<CODE> </CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>1</CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigint<CODE> </CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>1</CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigint<CODE> </CODE><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
This program simulates the push of the key combination <CODE>CTRL-C</CODE>
by sending the signal <TT>sigint</TT>. We obtain the following execution
trace: 
<PRE>
$ ocamlc -i -o ctrlc ctrlc.ml
val sigint_handle : int -&gt; unit
$ ctrlc
You just pushed CTRL-C
You pushed CTRL-C a second time
If you insist ...
</PRE>
<H5> sigalrm.</H5><A NAME="@fonctions437"></A>
Another frequently used signal is <TT>sigalrm</TT>, which is associated
with the system clock. It can be sent by the function <A NAME="@fonctions438"></A>


<PRE><BR># Unix.alarm<CODE> </CODE>;;<BR><CODE>- : int -&gt; int = &lt;fun&gt;</CODE><BR>

</PRE>

The argument specifies the number of seconds to wait before the
sending of the signal <TT>sigalrm</TT>. The return value indicates
the number of remaining seconds before the sending of a second signal,
or if there is no alarm set.<BR>
<BR>
We use this function and the associated signal to define the function
<TT>timeout</TT>, which starts the execution of another function and
interrupts it if neccessary, when the indicated time is elapsed.
More precisely, the function <EM>timeout</EM> takes as arguments a
function <EM>f</EM>, the argument <EM>arg</EM> expected by
<TT>f</TT>, the duration (<TT>time</TT>) of the ``<EM>timeout</EM>''
and the value (<TT>default_value</TT>) to be returned when the duration time
has elapsed.<BR>
<BR>
A <TT>timeout</TT> is handled as follows:
<OL type=1>
<LI>
 We modify the behavior associated with the signal <TT>sigalrm</TT>
so that a <TT>Timeout</TT> exception is thrown.

<LI> We take care to remember the behavior associated originally
with <TT>sigalrm</TT>, so that it can be restored.

<LI> We start the clock.

<LI> We distinguish two cases:
<OL type=a>
<LI>
 If everything goes well, we restore the original state of
<TT>sigalrm</TT> and return the value of the calculation.

<LI> If not, we restore <TT>sigalrm</TT>, and if the duration has elapsed,
we return the default value.
</OL>
</OL>
Here are the corresponding definitions and a small example:


<PRE><BR># <B>exception</B><CODE> </CODE>Timeout<CODE> </CODE>;;<BR><CODE>exception Timeout</CODE><BR># <B>let</B><CODE> </CODE>sigalrm_handler<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Sys<CODE>.</CODE>Signal_handle<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE>Timeout<TT>)</TT><CODE> </CODE>;;<BR><CODE>val sigalrm_handler : Sys.signal_behavior = Sys.Signal_handle &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>timeout<CODE> </CODE>f<CODE> </CODE>arg<CODE> </CODE>time<CODE> </CODE>default_value<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>old_behavior<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Sys.signal<CODE> </CODE>Sys.sigalrm<CODE> </CODE>sigalrm_handler<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>reset_sigalrm<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Sys.set_signal<CODE> </CODE>Sys.sigalrm<CODE> </CODE>old_behavior<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>ignore<CODE> </CODE><TT>(</TT>Unix.alarm<CODE> </CODE>time<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>res<CODE> </CODE><CODE>=</CODE><CODE> </CODE>f<CODE> </CODE>arg<CODE> </CODE><B>in</B><CODE> </CODE>reset_sigalrm<CODE> </CODE>()<CODE> </CODE>;<CODE> </CODE>res<CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>exc<CODE> </CODE>-&gt;<CODE> </CODE>reset_sigalrm<CODE> </CODE>()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>exc<CODE>=</CODE>Timeout<CODE> </CODE><B>then</B><CODE> </CODE>default_value<CODE> </CODE><B>else</B><CODE> </CODE>raise<CODE> </CODE>exc<CODE> </CODE>;;<BR><CODE>val timeout : ('a -&gt; 'b) -&gt; 'a -&gt; int -&gt; 'b -&gt; 'b = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>iterate<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>1</CODE><CODE> </CODE><B>to</B><CODE> </CODE>n<CODE> </CODE><B>do</B><CODE> </CODE>()<CODE> </CODE><B>done</B><CODE> </CODE>;<CODE> </CODE>n<CODE> </CODE>;;<BR><CODE>val iterate : int -&gt; int = &lt;fun&gt;</CODE><BR>

</PRE>



<PRE><BR>Printf.printf<CODE> </CODE><CODE>"1st execution : %d\n"</CODE><CODE> </CODE><TT>(</TT>timeout<CODE> </CODE>iterate<CODE> </CODE><CODE>1</CODE><CODE>0</CODE><CODE> </CODE><CODE>1</CODE><CODE> </CODE><TT>(</TT><CODE>-</CODE><CODE>1</CODE><TT>)</TT><TT>)</TT>;<BR>Printf.printf<CODE> </CODE><CODE>"2nd execution : %d\n"</CODE><CODE> </CODE><TT>(</TT>timeout<CODE> </CODE>iterate<CODE> </CODE><CODE>1</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE> </CODE><CODE>1</CODE><CODE> </CODE><TT>(</TT><CODE>-</CODE><CODE>1</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR>

</PRE>

<PRE>1st execution : 10
2nd execution : -1
- : unit = ()
</PRE>
<H5> sigusr1 and sigusr2.</H5>
<A NAME="@fonctions439"></A><A NAME="@fonctions440"></A>
These two signals are provided only for the programer. They are not
used by the operating system.<BR>
<BR>
In this example, reception of the signal
<TT>sigusr1</TT> by the child triggers the output of the content of
variable <TT>i</TT>.<BR>

<PRE>
<B>let</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE> </CODE>;;<BR><B>let</B><CODE> </CODE>write_i<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"signal received (%d) -- i=%d\n"</CODE><CODE> </CODE>s<CODE> </CODE><CODE>!</CODE>i<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;;<BR>Sys.set_signal<CODE> </CODE>Sys.sigusr1<CODE> </CODE><TT>(</TT>Sys<CODE>.</CODE>Signal_handle<CODE> </CODE>write_i<TT>)</TT><CODE> </CODE>;;<BR><BR><B>match</B><CODE> </CODE>Unix.fork<CODE> </CODE>()<CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><CODE> </CODE>incr<CODE> </CODE>i<CODE> </CODE><B>done</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE>pid<CODE> </CODE>-&gt;<CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigusr1<CODE> </CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>3</CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigusr1<CODE> </CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.sleep<CODE> </CODE><CODE>1</CODE><CODE> </CODE><CODE> </CODE>;<CODE> </CODE>Unix.kill<CODE> </CODE>pid<CODE> </CODE>Sys.sigkill<CODE> </CODE><CODE> </CODE><BR><BR>

</PRE>
<BR>
<BR>
Here is the trace of a program execution:<BR>

<PRE>
<CODE>signal received (10) -- i=0</CODE><BR><CODE>signal received (10) -- i=167722808</CODE><BR>

</PRE>
<BR>
<BR>
When we examine the trace, we can see that after having executed
the code associated with signal <TT>sigusr1</TT> the first time, the
child process continues to execute the loop and to increment
<EM>i</EM>.<BR>
<BR>

<H5> sigchld.</H5><A NAME="@fonctions441"></A>
This signal is sent to a parent on termination of a process.
We will use it to make a parent more attentive to the evolution
of its children. Here's how:
<OL type=1>
<LI>
 We define a function handling the signal
<TT>sigchld</TT>. It handles all terminated children on reception
of this signal<A NAME="text44" HREF="book-ora172.html#note44"><SUP><FONT SIZE=2>5</FONT></SUP></A> 
and terminates the parent when he does not have any more children
(exception <TT>Unix_error</TT>). In order not to block the parent
if not all his children are dead, we use <TT>waitpid</TT> instead of
<TT>wait</TT>.

<LI> The main program, after having redefined the reaction associated
with <TT>sigchld</TT>, loops to create five children. After this, the parent
does something else (loop <B>while</B> <EM>true</EM>) until his children
have terminated.
</OL>


<PRE>
<B>let</B><CODE> </CODE><B>rec</B><CODE> </CODE>sigchld_handle<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>pid<CODE>,</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.waitpid<CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>WNOHANG<CODE>]</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>pid<CODE> </CODE><CODE>&lt;&gt;</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE><TT>(</TT><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"%d is dead and buried at signal %d\n"</CODE><CODE> </CODE>pid<CODE> </CODE>s<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>sigchld_handle<CODE> </CODE>s<CODE> </CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>Unix<CODE>.</CODE>Unix_error<TT>(</TT><CODE>_,</CODE><CODE> </CODE><CODE>"waitpid"</CODE><CODE>,</CODE><CODE> </CODE><CODE>_</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>exit<CODE> </CODE><CODE>0</CODE><CODE> </CODE>;;<BR><BR><B>let</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>0</CODE><CODE> </CODE><BR><B>in</B><CODE> </CODE>Sys.set_signal<CODE> </CODE>Sys.sigchld<CODE> </CODE><TT>(</TT>Sys<CODE>.</CODE>Signal_handle<CODE> </CODE>sigchld_handle<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>Unix.fork()<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>let</B><CODE> </CODE>pid<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.getpid<CODE> </CODE>()<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Creation of %d\n"</CODE><CODE> </CODE>pid<CODE> </CODE>;<CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.sleep<CODE> </CODE><TT>(</TT>Random.int<CODE> </CODE><TT>(</TT><CODE>5</CODE><CODE>+</CODE><CODE> </CODE><CODE>!</CODE>i<TT>)</TT><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Termination of %d\n"</CODE><CODE> </CODE>pid<CODE> </CODE>;<CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>exit<CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>incr<CODE> </CODE>i<CODE> </CODE>;<CODE> </CODE><B>if</B><CODE> </CODE><CODE>!</CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>5</CODE><CODE> </CODE><B>then</B><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><CODE> </CODE>()<CODE> </CODE><B>done</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
We obtain the trace:<BR>

<PRE>
<CODE>Creation of 10658</CODE><BR><CODE>Creation of 10659</CODE><BR><CODE>Creation of 10662</CODE><BR><CODE>Creation of 10661</CODE><BR><CODE>Creation of 10660</CODE><BR><CODE>Termination of 10662</CODE><BR><CODE>10662 is dead and buried at signal 17</CODE><BR><CODE>Termination of 10658</CODE><BR><CODE>10658 is dead and buried at signal 17</CODE><BR><CODE>Termination of 10660</CODE><BR><CODE>Termination of 10659</CODE><BR><CODE>10660 is dead and buried at signal 17</CODE><BR><CODE>10659 is dead and buried at signal 17</CODE><BR><CODE>Termination of 10661</CODE><BR><CODE>10661 is dead and buried at signal 17</CODE><BR>

</PRE>
<BR>
<BR>
<BR>
<BR>

<BR>
<BR>
<HR>
<A HREF="book-ora167.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora169.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
